/*
  JSVKBrowserExtension.js

  Code copied from Virtual keyboard Browser Extension (trunk revision 301).
  Visit http://debugger.ru/demo/projects/virtualkeyboard/demo_inline.html for Virtual Keyboard

  The code is licensed under LGPL.

  Just modified some code to fit GownFull architecture.
*/
var JSVKBrowserExtension = Base.extend({
	offsetCalculator: null,
	keys: null,

	constructor: null,
	init: function()
	{
		this.keys = {
		'selectionStart' : '__DSselectionStart'
		,'selectionEnd' : '__DSselectionEnd'
		}
	},
	isFunction: function (prop /* :Object */) /* :Boolean */ {
	  return (typeof prop == 'function');
	},
	getOffset: function (el /* :HTMLElement */) /* :Object */ {
		var fixBrowserQuirks = true
		,o = el
		,left = 0
		,top = 0
		,width = 0
		,height = 0
		,parentNode = null
		,offsetParent = null;
		
		if (o==null) return null;
		
		offsetParent = o.offsetParent;
		var originalObject = o
		,el = o; // "el" will be nodes as we walk up, "o" will be saved for offsetParent references
		while (el.parentNode!=null) {
		el = el.parentNode;
		if (el.offsetParent==null) {
		}
		else {
			var considerScroll = true;
			/*
			In Opera, if parentNode of the first object is scrollable, then offsetLeft/offsetTop already 
			take its scroll position into account. If elements further up the chain are scrollable, their 
			scroll offsets still need to be added in. And for some reason, TR nodes have a scrolltop value
			which must be ignored.
			*/
			if (fixBrowserQuirks && window.opera) {
			if (el==originalObject.parentNode || el.nodeName=="TR") {
			considerScroll = false;
			}
			}
			if (considerScroll) {
			if (el.scrollTop && el.scrollTop>0) {
			top -= el.scrollTop;
			}
			if (el.scrollLeft && el.scrollLeft>0) {
			left -= el.scrollLeft;
			}
			}
		}
		// If this node is also the offsetParent, add on the offsets and reset to the new offsetParent
		if (el == offsetParent) {
//			Debug.trace(0,'%s (%d,%d)',el,el.offsetLeft,el.offsetTop);
			// added by wonghang, special treatment for safari
			if((GownFullBrowserDetect.current_engine == GownFullBrowserDetect.ENGINE_WEBKIT ||
			   GownFullBrowserDetect.current_engine == GownFullBrowserDetect.ENGINE_KHTML) &&
			    (el.style.position == 'absolute' || el.style.position == 'fixed'))
			{
				left += o.offsetLeft;
				top += o.offsetTop;
				left += el.offsetLeft;
				top += el.offsetTop;
				break;
			}
			else {
				left += o.offsetLeft;
				if (el.clientLeft && el.nodeName!="TABLE") { 
					left += el.clientLeft;
				}
				top += o.offsetTop;
				if (el.clientTop && el.nodeName!="TABLE") {
					top += el.clientTop;
				}
				o = el;
				if (o.offsetParent==null) {
					if (o.offsetLeft) {
						left += o.offsetLeft;
					}
					if (o.offsetTop) {
						top += o.offsetTop;
					}
				}
			}

			offsetParent = o.offsetParent;
		}
		}
		
		
		if (originalObject.offsetWidth) {
		width = originalObject.offsetWidth;
		}
		if (originalObject.offsetHeight) {
		height = originalObject.offsetHeight;
		}
		
		return {'x':left, 'y':top, 'width':width, 'height':height};
	},
	getSelectionOffset: function (el) {
		var range;
		if (this.isFunction(el.setSelectionRange)) {
			/*
			*  For Mozilla
			*/
			if (!this.offsetCalculator) {
			/*
			*  create hidden div, which will 'emulate' the textarea
			*  it's put 'below the ground', because toggling block/none is too expensive
			*/
			this.offsetCalculator = document.createElement('td');
			
			// Added by wonghang (wonghang@gmail.com)
			this.offsetCalculator.id = 'JSVK_offsetCalculator'; // for Firebug

			document.body.appendChild(this.offsetCalculator);
			}
			/*
			*  store the reference to last-checked object, to prevent recalculation of styles
			*/
			if (this.offsetCalculator[this.keys.prevCalcNode] != el) {
			this.offsetCalculator[this.keys.prevCalcNode] = el;
			var cs = document.defaultView.getComputedStyle(el, null);
			for (var i in cs) {
				try {if (cs[i]) offsetCalculator.style[i] = cs[i];}catch(e){}
			}
			this.offsetCalculator.style.overflow = 'auto';
			this.offsetCalculator.style.position = 'absolute';
			this.offsetCalculator.style.visibility = 'hidden';
			this.offsetCalculator.style.zIndex = '-10';
			this.offsetCalculator.style.left="-10000px";
			this.offsetCalculator.style.top="-10000px";
			this.offsetCalculator.style.backgroundColor = 'yellow';
		
			}
			/*
			*  caclulate offsets to target and move div right below it
			*/
			var range = document.createRange()
			,val = el.value || " ";
		
			if ('input'==el.tagName.toLowerCase()) {
			this.offsetCalculator.style.width = 'auto'
			this.offsetCalculator.style.whiteSpace =  'nowrap';
			} else {
			this.offsetCalculator.style.whiteSpace = 'off'==el.getAttribute('wrap')?"pre":"";
			}
			
			val = val.replace(/\x20\x20/g,"\x20\xa0")
			this.offsetCalculator.innerHTML = ( val.substr(0,el.selectionStart)+"<span></span>"
							+val.substr(el.selectionStart)).replace(/\n/g,"<br />")
										.replace(/\t/g,"<em style=\"white-space:pre\">\t</em>")
			/*
			*  span is used to find the offsets
			*/
			var span = this.offsetCalculator.getElementsByTagName('span')[0];
			span.style.borderLeft = '1px solid red';
			range.offsetLeft = span.offsetLeft - el.scrollLeft;
			range.offsetTop = span.offsetTop - el.scrollTop;
			range.offsetHeight = span.offsetHeight;
			span = null;
			/*
			*  this is required, because Mozilla sometimes looses visual cursor, if div is not hidden
			*/
		} else if (document.selection && document.selection.createRange) {
			/*
			*  For IE
			*/
			range = document.selection.createRange();
			/*
			*  IE does not allow to calculate lineHeight, but this check is easy
			*/
			range.offsetHeight = Math.round(range.boundingHeight/(range.text.replace(/[^\n]/g,"").length+1));
			if (el.tagName && 'textarea'==el.tagName.toLowerCase()) {
			var xy = this.getOffset(el)
			range = {
				'offsetTop' : range.offsetTop-xy.y
				,'offsetLeft' : range.offsetLeft-xy.x
				,'offsetHeight' : range.offsetHeight
			}
			}
		}
		if (range) {
			return {'x': range.offsetLeft, 'y': range.offsetTop, 'h': range.offsetHeight};
		}
		return {'x': 0, 'y': 0, 'h': 0};
	}
});
